
#ifndef _BIND_H
#define _BIND_H

#include "Function.h"

namespace Bind
{
	/*<@ Static/global function */
	template<class FunRet>
	inline Function::Functor* bind(FunRet(*funPtr)())
	{
		return new Function::Functor0<FunRet(*)()>(funPtr);
	}
	
	template<class FunRet, class Type1, class Para1>
	inline Function::Functor* bind(FunRet(*funPtr)(Type1), const Para1& p1)
	{
		return new Function::Functor1<FunRet(*)(Type1), Para1>(funPtr, p1);
	}

	template<class FunRet, class Type1, class Type2, class Para1,
		     class Para2>
	inline Function::Functor* bind(FunRet(*funPtr)(Type1, Type2), const Para1& p1, 
						  const Para2& p2)
	{
		return new Function::Functor2<FunRet(*)(Type1, Type2), Para1, Para2>
			(funPtr, p1, p2);
	}

	template<class FunRet, class Type1, class Type2, class Type3, 
			 class Para1, class Para2, class Para3>
	inline Function::Functor* bind(FunRet(*funPtr)(Type1, Type2, Type3), const Para1& p1, 
						  const Para2& p2, const Para3& p3)
	{
		return new Function::Functor3<FunRet(*)(Type1, Type2, Type3), Para1, Para2, Para3>
			(funPtr, p1, p2, p3);
	}

	template<class FunRet, class Type1, class Type2, class Type3,
		     class Type4, class Para1, class Para2, class Para3,
			 class Para4>
	inline Function::Functor* bind(FunRet(*funPtr)(Type1, Type2, Type3, Type4), const Para1& p1,
								   const Para2& p2, const Para3& p3, const Para4& p4)
	{
		return new Function::Functor4<FunRet(*)(Type1, Type2, Type3, Type4), Para1, Para2, Para3, Para4>
			(funPtr, p1, p2, p3, p4);

	}

	template<class FunRet, class Type1, class Type2, class Type3,
		     class Type4, class Type5, class Para1, class Para2,
			 class Para3, class Para4, class Para5>
	inline Function::Functor* bind(FunRet(*funPtr)(Type1, Type2, Type3, Type4, Type5), const Para1& p1,
		                           const Para2& p2, const Para3& p3, const Para4& p4, const Para5& p5)
	{
		return new Function::Functor5<FunRet(*)(Type1, Type2, Type3, Type4, Type5), Para1, Para2, Para3, Para4, Para5>
			(funPtr, p1, p2, p3, p4, p5);
		
	}

	template<class FunRet, class Type1, class Type2, class Type3,
		class Type4, class Type5, class Type6, class Para1, class Para2,
		class Para3, class Para4, class Para5, class Para6>
		inline Function::Functor* bind(FunRet(*funPtr)(Type1, Type2, Type3, Type4, Type5, Type6), const Para1& p1,
		const Para2& p2, const Para3& p3, const Para4& p4, const Para5& p5, const Para6& p6)
	{
		return new Function::Functor6<FunRet(*)(Type1, Type2, Type3, Type4, Type5, Type6),Para1, Para2, Para3, Para4, Para5, Para6>
			(funPtr, p1, p2, p3, p4, p5, p6);
		
	}


	/*<@ Member Function */
	template<class ObjPtr, class Obj, class FunRet>
	inline Function::Functor* bind(const ObjPtr& objPtr, FunRet(Obj::*memFunPtr)())
	{
		return new Function::MemFunctor0<ObjPtr, FunRet(Obj::*)()>(objPtr, memFunPtr);
	}

 	template<class ObjPtr, class Obj, class FunRet, class Type1, class Para1>
	inline Function::Functor* bind(const ObjPtr& objPtr, FunRet(Obj::*memFunPtr)(Type1), const Para1& p1)
	{
		return new Function::MemFunctor1<ObjPtr, FunRet(Obj::*)(Type1), Para1>
			(objPtr, memFunPtr, p1);
	}

	template<class ObjPtr, class Obj, class FunRet, class Type1, class Type2, class Para1, class Para2>
	inline Function::Functor* bind(const ObjPtr& objPtr, FunRet(Obj::*memFunPtr)(Type1, Type2), const Para1& p1, 
								   const Para2& p2)
	{
		return new Function::MemFunctor2<ObjPtr, FunRet(Obj::*)(Type1, Type2), Para1, Para2>
			(objPtr, memFunPtr, p1, p2);
	}

	template<class ObjPtr, class Obj, class FunRet, class Type1, class Type2, class Type3, class Para1, class Para2, class Para3>
	inline Function::Functor* bind(const ObjPtr& objPtr, FunRet(Obj::*memFunPtr)(Type1, Type2, Type3), 
								   const Para1& p1, const Para2& p2, const Para3& p3)
	{
		return new Function::MemFunctor3<ObjPtr, FunRet(Obj::*)(Type1, Type2, Type3), Para1, Para2, Para3>
			(objPtr, memFunPtr, p1, p2, p3);
	}

	template<class ObjPtr, class Obj, class FunRet, class Type1, class Type2, class Type3, class Type4, 
			 class Para1, class Para2, class Para3, class Para4>
	inline Function::Functor* bind(const ObjPtr& objPtr, FunRet(Obj::*memFunPtr)(Type1, Type2, Type3, Type4),
								   const Para1& p1, const Para2& p2, const Para3& p3, const Para4& p4)
	{
		return new Function::MemFunctor4<ObjPtr, FunRet(Obj::*)(Type1, Type2, Type3, Type4), Para1, Para2, Para3, Para4>
			(objPtr, memFunPtr, p1, p2, p3, p4);
	}

	template<class ObjPtr, class Obj, class FunRet, class Type1, class Type2, class Type3, class Type4, class Type5, 
			 class Para1, class Para2, class Para3, class Para4, class Para5>
	inline Function::Functor* bind(const ObjPtr& objPtr, FunRet(Obj::*memFunPtr)(Type1, Type2, Type3, Type4, Type5), 
								   const Para1& p1, const Para2& p2, const Para3& p3, const Para4& p4, const Para5& p5)
	{
		return new Function::MemFunctor5<ObjPtr, FunRet(Obj::*)(Type1, Type2, Type3, Type4, Type5), Para1, Para2, Para3, Para4, Para5>
			(objPtr, memFunPtr, p1, p2, p3, p4, p5);
	}

	template<class ObjPtr, class Obj, class FunRet, class Type1, class Type2, class Type3, class Type4, class Type5, class Type6,
		     class Para1, class Para2, class Para3, class Para4, class Para5, class Para6>
	inline Function::Functor* bind(const ObjPtr& objPtr, FunRet(Obj::*memFunPtr)(Type1, Type2, Type3, Type4, Type5, Type6), 
								   const Para1& p1, const Para2& p2, const Para3& p3, const Para4& p4, const Para5& p5, const Para6& p6)
	{
		return new Function::MemFunctor6<ObjPtr, FunRet(Obj::*)(Type1, Type2, Type3, Type4, Type5, Type6), Para1, Para2, Para3, Para4, Para5, Para6>
			(objPtr, memFunPtr, p1, p2, p3, p4, p5, p6);
	}

}

#endif /*_BIND_H*/
